// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "NcAPI.h"


#ifndef FALSE 
#define FALSE (1 == 0)
#endif

#ifndef TRUE
#define TRUE (0 == 0)
#endif

#define N    5

extern int ninf_error_code;
int verbose = FALSE;

/****************************************/
int compare_float(float a, float b){
  if (a == 0.0 || b == 0.0)
    return (a == b);
  return (fabs((a - b) / a)) < 0.000001;
}

int compare_double(double a, double b){
  if (a == 0.0 || b == 0.0)
    return (a == b);
  return (fabs((a - b) / a)) < 0.00000001;
}
/****************************************/

int char_test(){
  char a[N], b[N];
  int i, success = TRUE;
  for (i = 0; i < N; i++){
    a[i] = i; b[i] = 0;
  }
  printf("char_testing: ");
  if (NinfCall("diag/char_test", (char)N, a, b) != NINF_NO_ERROR){
    NinfPerror("diag/char_test");
    return FALSE;
  }
  for (i = 0; i < N; i++){
    if (a[i] != b[i]){
      success = FALSE;
      if (verbose) 
	printf("char_test: a[%d](%d) != b[%d](%d)\n", i, a[i], i, b[i]);
    }
  }
  return success;
}

int short_test(){
  short a[N], b[N];
  int i, success = TRUE;
  for (i = 0; i < N; i++){
    a[i] = i; b[i] = 0;
  }
  printf("short_testing: ");
  if (NinfCall("diag/short_test", (short)N, a, b) != NINF_NO_ERROR){
    NinfPerror("diag/short_test");
    return FALSE;
  }
  for (i = 0; i < N; i++){
    if (a[i] != b[i]){
      success = FALSE;
      if (verbose) 
	printf("short_test: a[%d](%d) != b[%d](%d)\n", i, a[i], i, b[i]);
    }
  }
  return success;
}

int int_test(){
  int a[N], b[N];
  int i, success = TRUE;
  for (i = 0; i < N; i++){
    a[i] = i; b[i] = 0;
  }
  printf("int_testing: ");
  if (NinfCall("diag/int_test", N, a, b) != NINF_NO_ERROR){
    NinfPerror("diag/int_test");
    return FALSE;
  }
  for (i = 0; i < N; i++){
    if (a[i] != b[i]){
      success = FALSE;
      if (verbose) 
	printf("int_test: a[%d](%d) != b[%d](%d)\n", i, a[i], i, b[i]);
    }
  }
  return success;
}

int float_test(){
  float a[N], b[N];
  int i, success = TRUE;
  for (i = 0; i < N; i++){
    a[i] = i; b[i] = 0;
  }
  printf("float_testing: ");
  if (NinfCall("diag/float_test", N, a, b) != NINF_NO_ERROR){
    NinfPerror("diag/float_test");
    return FALSE;
  }
  for (i = 0; i < N; i++){
    if (!compare_float(a[i], b[i])){
      success = FALSE;
      if (verbose) 
	printf("float_test: a[%d](%f) != b[%d](%f)\n", i, a[i], i, b[i]);
    }
  }
  return success;
}
int double_test(){
  double a[N], b[N];
  int i, success = TRUE;
  for (i = 0; i < N; i++){
    a[i] = i; b[i] = 0;
  }
  printf("double_testing: ");
  if (NinfCall("diag/double_test", N, a, b) != NINF_NO_ERROR){
    NinfPerror("diag/double_test");
    return FALSE;
  }
  for (i = 0; i < N; i++){
    if (!compare_double(a[i],b[i])){
      success = FALSE;
      if (verbose) 
	printf("double_test: a[%d](%lf) != b[%d](%lf)\n", i, a[i], i, b[i]);
    }
  }
  return success;
}

int dcomplex_test(){
  double a[N*2], b[N*2];
  int i, success = TRUE;
  for (i = 0; i < N; i++){
    a[i * 2] = i; a[i*2+1] = i+0.1; 
    b[i * 2] = 0; b[i*2+1] = 0; 
  }
  printf("dcomplex_testing: ");
  if (NinfCall("diag/dcomplex_test", N, a, b) != NINF_NO_ERROR){
    NinfPerror("diag/dcomplex_test");
    return FALSE;
  }
  for (i = 0; i < N; i++){
    if (!compare_double(a[i*2], b[i*2]) || 
	!compare_double(a[i*2+1], b[i*2+1])){
      success = FALSE;
      if (verbose) 
	printf("dcomplex_test: a[%d](%lf, %lf) != b[%d](%lf, %lf)\n", 
	       i, a[i*2], a[i*2+1], i, b[i*2], b[i*2+1]);
    }
  }
  return success;
}

int scomplex_test(){
  float a[N*2], b[N*2];
  int i, success = TRUE;
  for (i = 0; i < N; i++){
    a[i * 2] = i; a[i*2+1] = i+0.1; 
    b[i * 2] = 0; b[i*2+1] = 0; 
  }
  printf("scomplex_testing: ");
  if (NinfCall("diag/scomplex_test", N, a, b) != NINF_NO_ERROR){
    NinfPerror("diag/scomplex_test");
    return FALSE;
  }
  for (i = 0; i < N; i++){
    if (!compare_float(a[i*2], b[i*2]) ||
	!compare_float(a[i*2+1], b[i*2+1])){
      success = FALSE;
      if (verbose) 
	printf("scomplex_test: a[%d](%f, %f) != b[%d](%f, %f)\n", 
	       i, a[i*2], a[i*2+1], i, b[i*2], b[i*2+1]);
    }
  }
  return success;
}


int lda_test(){
  double a[N][N], b;
  int i,j;

  for (i = 0; i < N; i++)
    for (j = 0; j < N; j++)
      a[i][j] = i * N + j;

  printf("lda_testing: ");
  if (NinfCall("diag/lda_test", 3, 3, N, a, &b)){
    NinfPerror("diag/lda_test");
    return FALSE;
  }
  if (b != 54.0)
    return FALSE;
  return TRUE;
}

int lda_test2(){
  double a[N][N], b;
  int i,j;

  for (i = 0; i < N; i++)
    for (j = 0; j < N; j++)
      a[i][j] = i * N + j;

  printf("lda_testing2: ");
  if (NinfCall("diag/lda_test2", 3, 3, N, a, &b)){
    NinfPerror("diag/lda_test2");
    return FALSE;
  }
  if (b != 54.0)
    return FALSE;
  return TRUE;
}

#include <string.h>
#include <stdlib.h>
#define TEST_STR_LENGTH 1000

int string_test(){
  char * buffer = NULL;
  char * teststring;
  int success = TRUE;
  int i;
    
  if ((teststring = (char *)malloc(TEST_STR_LENGTH)) == NULL){
    fprintf(stderr, "failed to malloc string length: %d\n", TEST_STR_LENGTH);
    return FALSE;
  }
  for (i = 0; i < TEST_STR_LENGTH -1; i++)
    *(teststring + i) = (i % 10) + '0';
  *(teststring + i) = '\0';

  printf("string_testing: ");
  if (NinfCall("diag/string_test", teststring, &buffer) != NINF_NO_ERROR){
    NinfPerror("string_test: ");
    return FALSE;
  }
  if (strcmp(teststring, buffer) != 0){
    if (verbose) printf("%s != %s\n", teststring, buffer);
    return FALSE;
  }
  return TRUE;
}

#define SKIP 3
#define TIMES 10
int skip_int_test(){
  int in[SKIP * TIMES];
  int out[SKIP * TIMES];
  int i, j;

  printf("skip_testing: ");
  for (i = 0; i < SKIP * TIMES; i++)
    in[i] = i;
  for (i = 0; i < SKIP; i++){
    if (NinfCall("diag/skip_int_test", SKIP * TIMES, i, SKIP * TIMES, SKIP, in, out)
	!= NINF_NO_ERROR){
      NinfPerror("skip_int_test: ");
      return FALSE;
    }
  }
  for (i = 0; i < SKIP * TIMES; i++){
    if (out[i] != (SKIP * TIMES - i -1))
      return FALSE;
    if (verbose) printf("%d ", out[i]);
  }
  if (verbose) printf("\n");
  return TRUE;
}

int skip_char_test(){
  char in[SKIP * TIMES];
  char out[SKIP * TIMES];
  int i, j;

  printf("skip_char_testing: ");
  for (i = 0; i < SKIP * TIMES; i++)
    in[i] = i;
  for (i = 0; i < SKIP; i++){
    if (NinfCall("diag/skip_char_test", SKIP * TIMES, i, SKIP * TIMES, SKIP, in, out)
	!= NINF_NO_ERROR){
      NinfPerror("skip_char_test: ");
      return FALSE;
    }
  }
  for (i = 0; i < SKIP * TIMES; i++){
    if (out[i] != (SKIP * TIMES - i -1))
      return FALSE;
    if (verbose) printf("%d ", out[i]);
  }
  if (verbose) printf("\n");
  return TRUE;
}

int skip_short_test(){
  short in[SKIP * TIMES];
  short out[SKIP * TIMES];
  int i, j;
  int success = TRUE;

  printf("skip_short_testing: ");
  for (i = 0; i < SKIP * TIMES; i++)
    in[i] = i;
  for (i = 0; i < SKIP; i++){
    if (NinfCall("diag/skip_short_test", SKIP * TIMES, i, SKIP * TIMES, SKIP, in, out)
	!= NINF_NO_ERROR){
      NinfPerror("skip_short_test: ");
      return FALSE;
    }
  }
  for (i = 0; i < SKIP * TIMES; i++){
    if (verbose) printf("%d ", out[i]);
    if (out[i] != (SKIP * TIMES - i -1))
      success = FALSE;
  }
  if (verbose) printf("\n");
  return success;
}

int skip_scomplex_test(){
  float in[SKIP * TIMES * 2];
  float out[SKIP * TIMES * 2];
  int i, j;
  int success = TRUE;

  printf("skip_scomplex_testing: ");
  for (i = 0; i < SKIP * TIMES; i++){
    in[i*2]   = i;
    in[i*2+1] = i + 0.1;
  }
  for (i = 0; i < SKIP; i++){
    if (NinfCall("diag/skip_scomplex_test", SKIP * TIMES, i, SKIP * TIMES, SKIP, in, out)
	!= NINF_NO_ERROR){
      NinfPerror("skip_scomplex_test: ");
      return FALSE;
    }
  }
  for (i = 0; i < SKIP * TIMES; i++){
    if (!compare_float(out[i * 2], (SKIP * TIMES - i -1)) ||
	!compare_float(out[i*2+1], (float)(SKIP * TIMES - i -1 + 0.1)))
      success = FALSE;
    if (verbose) printf("(%f, %f)", out[i*2],out[i*2+1]);
  }
  if (verbose) printf("\n");
  return success;
}


int skip_dcomplex_test(){
  double in[SKIP * TIMES * 2];
  double out[SKIP * TIMES * 2];
  int i, j;
  int success = TRUE;

  printf("skip_dcomplex_testing: ");
  for (i = 0; i < SKIP * TIMES; i++){
    in[i*2]   = i;
    in[i*2+1] = i + 0.1;
  }
  for (i = 0; i < SKIP; i++){
    if (NinfCall("diag/skip_dcomplex_test", SKIP * TIMES, i, SKIP * TIMES, SKIP, in, out)
	!= NINF_NO_ERROR){
      NinfPerror("skip_dcomplex_test: ");
      return FALSE;
    }
  }
  for (i = 0; i < SKIP * TIMES; i++){
    if (!compare_double(out[i * 2],(SKIP * TIMES - i -1)) ||
	!compare_double(out[i*2+1],(SKIP * TIMES - i -1)+0.1))
      success = FALSE;
    if (verbose) printf("(%lf, %lf)", out[i*2],out[i*2+1]);
  }
  if (verbose) printf("\n");
  return success;
}

int expr_test(){
  int out[10];
  printf("expr_testing: ");
  if (NinfCall("diag/expr_test", 0, 1, 10, out) != NINF_NO_ERROR){
    NinfPerror("expr_test: ");
    return FALSE;
  }
  return TRUE;
}

int filename_test(){
  const char * in, * out;

  printf("filename_testing: ");

  in =  "DataTest.cpp";
  out = "DataTest.cpp.compare";

  if (in == NULL || out == NULL)
    return FALSE;

  if (NinfCall("diag/filename_test", in, out) != 0){
    NinfPerror("filename_test: ");
    return FALSE;
  }
  if (system("cmp DataTest.cpp DataTest.cpp.compare") != 0)
    return FALSE;
  return TRUE;
}


main(int argc, char ** argv)
{
    argc = NinfParseArg(argc, argv);

    while (argc > 1){
      argv++;
      if (strcasecmp(*(argv), "-verbose") == 0)
	verbose = TRUE;
      //      if (strcasecmp(*(argv), "-debug") == 0)
      //	ninf_debug_flag = TRUE;
      argc--;
    }

    if (char_test())  {printf("\tOK\n");} else { printf("\tfailed\n");} 
    if (short_test()) {printf("\tOK\n");} else { printf("\tfailed\n");}
    if (int_test())   {printf("\tOK\n");} else { printf("\tfailed\n");}
    if (float_test()) {printf("\tOK\n");} else { printf("\tfailed\n");}
    if (double_test()){printf("\tOK\n");} else { printf("\tfailed\n");}
    if (string_test()){printf("\tOK\n");} else { printf("\tfailed\n");}
    if (scomplex_test()){printf("\tOK\n");} else { printf("\tfailed\n");}
    if (dcomplex_test()){printf("\tOK\n");} else { printf("\tfailed\n");}

    if (skip_int_test())  {printf("\tOK\n");} else { printf("\tfailed\n");}
    if (skip_char_test())  {printf("\tOK\n");} else { printf("\tfailed\n");}
    if (skip_short_test())  {printf("\tOK\n");} else { printf("\tfailed\n");}

    if (lda_test())   {printf("\tOK\n");} else { printf("\tfailed\n");}
    if (lda_test2())  {printf("\tOK\n");} else { printf("\tfailed\n");}
    if (expr_test())  {printf("\tOK\n");} else { printf("\tfailed\n");}
    if (filename_test())
      {printf("\tOK\n");} else { printf("\tfailed\n");}

    NinfFinalize();

}

